#ifndef WRAP_PTHREAD_H
#define WRAP_PTHREAD_H

#include "utility/feature.h"

#include <pthread.h>

namespace Wrap {

/// @see https://man7.org/linux/man-pages/man3/pthread_attr_init.3.html
/// @param attr The pthread_attr_init() function initializes the thread
/// attributes object pointed to by @c attr with default attribute values.
/// After this call, individual attributes of the object can be set using
/// various related functions (listed under SEE ALSO), and then the object can
/// be used in one or more pthread_create(3) calls that create threads.
/// @return On success, these functions return 0; on error, they return a
/// nonzero error number.
int pthread_attr_init_(pthread_attr_t *attr);

/// @see https://man7.org/linux/man-pages/man3/pthread_create.3.html
/// @return On success, pthread_create() returns 0; on error, it returns an
/// error number, and the contents of @c *newthread are undefined.
/// @throw EAGAIN Insufficient resources to create another thread.
/// @throw EAGAIN A system-imposed limit on the number of threads was
/// encountered. There are a number of limits that may trigger this error: the
/// RLIMIT_NPROC soft resource limit (set via setrlimit(2)), which limits the
/// number of processes and threads for a real user ID, was reached; the
/// kernel's system-wide limit on the number of processes and threads,
/// /proc/sys/kernel/threads-max, was reached (see proc(5)); or the maximum
/// number of PIDs, /proc/sys/kernel/pid_max, was reached (see proc(5)).
/// @throw EINVAL Invalid settings in @c attr.
/// @throw EPERM  No permission to set the scheduling policy and parameters
/// specified in @c attr.
int pthread_create_(
    pthread_t *newthread, const pthread_attr_t *attr,
    void *(*startRoutine)(void *), void *arg);

/// @see https://man7.org/linux/man-pages/man3/pthread_exit.3.html
/// @param retval The pthread_exit() function terminates the calling thread and
/// returns a value via @c retval that (if the thread is joinable) is available
/// to another thread in the same process that calls pthread_join(3).
NORETURN void pthread_exit_(void *retval);

/// @see https://man7.org/linux/man-pages/man3/pthread_getspecific.3p.html
/// @param key The pthread_getspecific() function shall return the value
/// currently bound to the specified @c key on behalf of the calling thread.
/// @return The pthread_getspecific() function shall return the thread-specific
/// data value associated with the given @c key. If no thread-specific data
/// value is associated with @c key, then the value NULL shall be returned.
void *pthread_getspecific_(pthread_key_t key);

/// @see https://man7.org/linux/man-pages/man3/pthread_key_create.3p.html
/// @param key The pthread_key_create() function shall create a thread-specific
/// data @c key visible to all threads in the process.
/// @param destrFunction An optional @c destrFunction function may be
/// associated with each @c key value.
/// @return If successful, the pthread_key_create() function shall store the
/// newly created @c key value at @c *key and shall return zero. Otherwise, an
/// error number shall be returned to indicate the error.
/// @throw EAGAIN The system lacked the necessary resources to create another
/// thread-specific data key, or the system-imposed limit on the total number of
/// keys per process {PTHREAD_KEYS_MAX} has been exceeded.
/// @throw ENOMEM Insufficient memory exists to create the key.
int pthread_key_create_(pthread_key_t *key, void (*destrFunctioin)(void *));

/// @see https://man7.org/linux/man-pages/man3/pthread_key_delete.3p.html
/// @param key The pthread_key_delete() function shall delete a thread-specific
/// data @c key previously returned by pthread_key_create().
/// @return If successful, the pthread_key_delete() function shall return zero;
/// otherwise, an error number shall be returned to indicate the error.
int pthread_key_delete_(pthread_key_t key);

/// @see https://man7.org/linux/man-pages/man3/pthread_self.3.html
/// @return This function always succeeds, returning the calling thread's ID.
pthread_t pthread_self_();

/// @see https://man7.org/linux/man-pages/man3/pthread_setaffinity_np.3.html
/// @param th The pthread_setaffinity_np() function sets the CPU affinity mask
/// of the thread @c th
/// @param cpuset to the CPU set pointed to by @c cpuset. If the call is
/// successful, and the thread is not currently running on one of the CPUs in
/// @c cpuset, then it is migrated to one of those CPUs.
/// @param cpusetsize The argument @c cpusetsize is the length (in bytes) of
/// the buffer pointed to by @c cpuset.
/// @return On success, these functions return 0; on error, they return a
/// nonzero error number.
/// @throw EFAULT A supplied memory address was invalid.
/// @throw EINVAL The affinity bit mask @c cpuset->mask contains no processors
/// that are currently physically on the system and permitted to the thread
/// according to any restrictions that may be imposed by the "cpuset" mechanism
/// described in cpuset(7).
/// @throw EINVAL @c cpuset specified a CPU that was outside the set supported
/// by the kernel.  (The kernel configuration option CONFIG_NR_CPUS defines the
/// range of the set supported by the kernel data type used to represent CPU
/// sets.)
/// @throw ESRCH  No thread with the ID @c th could be found.
int pthread_setaffinity_np_(
    pthread_t th, size_t cpusetsize, const cpu_set_t *cpuset);

/// @see https://man7.org/linux/man-pages/man3/pthread_setspecific.3p.html
/// @param pointer The pthread_setspecific() function shall associate a
/// thread-specific @c pointer
/// @param key with a @c key obtained via a previous call to
/// pthread_key_create().
/// @return If successful, the pthread_setspecific() function shall return
/// zero; otherwise, an error number shall be returned to indicate the error.
/// @throw ENOMEM Insufficient memory exists to associate the non-NULL value
/// with the key.
int pthread_setspecific_(pthread_key_t key, const void *pointer);


}


#endif